/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.das.commonmodel.entity;

//import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnore;

import com.inspur.edp.caf.cef.schema.base.structure.impl.DefaultEntityObject;
import com.inspur.edp.caf.cef.schema.datatype.StructuredType;
import com.inspur.edp.caf.cef.schema.element.Operation;
import com.inspur.edp.caf.cef.schema.structure.CommonStructure;
import com.inspur.edp.caf.cef.schema.structure.EntityObject;
import com.inspur.edp.caf.cef.schema.structure.EntityRelation;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.element.GspCommonAssociation;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.entity.DataTypeAssemblyInfo;
import com.inspur.edp.cef.designtime.api.variable.CommonVariableEntity;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
/**
 * The Definition Of Common Model
 *
 * @ClassName: GspCommonModel
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public class GspCommonModel extends AbstractMetadataContent implements IGspCommonModel, Cloneable, EntityObject {
	public GspCommonModel() {
		setVariables(new CommonVariableEntity());
		setIsVirtual(false);
	}

	// region 字段和属性
	private boolean isVirtual;
	private GspCommonObject mainObject;
	private CommonVariableEntity variables;
	private final HashMap<String, String> extendNodeList = new HashMap<String, String>();
	// C# TO JAVA CONVERTER TODO TASK: Java annotations will not correspond to .NET
	// attributes:
	// [NonSerialized]
	private Map<String, Object> extProperties;

	/**
	 * 扩展成员,用于扩展方法暂存运行时临时数据
	 */
	public Map<String, Object> getExtProperties() {
		return (extProperties != null) ? extProperties : (extProperties = new HashMap<String, Object>());
	}

	/**
	 * 是否简化生成代码
	 */
	private boolean isSimplifyGen;

	//建好Bean生成代码
	private boolean isSimpBeanConfig = false;

	private String extendType = "";

	private String privateID;

	public final String getID() {
		return privateID;
	}

	public final void setID(String value) {
		privateID = value;
	}

	private String privateCode;

	public final String getCode() {
		this.privateCode = super.getCode();
		return privateCode;
	}

	public final void setCode(String value) {
		privateCode = value;
		super.setCode(value);
	}

	public final String getFlag() {
		return flag;
	}

	public final void setFlag(String flag) {
		this.flag = flag;
	}

	//V1:旧BE编辑器 V2:新BE编辑器
	private String flag;

	private String privateName;

	public final String getName() {
		this.privateName =super.getName();
		return privateName;
	}

	public final void setName(String value) {
		privateName = value;
		super.setName(value);
	}

	/**
	 * 标签
	 */
	private List<String> beLabel;
	public List<String> getBeLabel() {
		if(beLabel==null){
			beLabel=new ArrayList<String>();
		    return beLabel;
		}
		return beLabel;
	}
	public void setBeLabel(List<String> value) {
		beLabel=value;
	}
	/**
	 * 是否虚拟
	 */
	public boolean getIsVirtual() {
		return isVirtual;
	}

	public void setIsVirtual(boolean value) {
		isVirtual = value;
	}

	/**
	 * 扩展类型
	 */
	public String getExtendType() {
		return extendType;
	}

	public void setExtendType(String value) {
		extendType = value;
	}

	/**
	 * 模型实体类型，表示不同模型实例的类型
	 */
	private String privateEntityType;

	public final String getEntityType() {
		return privateEntityType;
	}

	public final void setEntityType(String value) {
		privateEntityType = value;
	}

	/**
	 * 扩展结点列表
	 */
	// [Newtonsoft.Json.jsonIgnore()]
	public HashMap<String, String> getExtendNodeList() {
		return extendNodeList;
	}

	/**
	 * 主实体
	 */
	@Override
	public GspCommonObject getMainObject() {
		return mainObject;
	}

	@Override
	public void setMainObject(IGspCommonObject value) {
		setCmMainObject((GspCommonObject) value);
	}

	public void setCmMainObject(GspCommonObject value) {
		if (mainObject != null) {
			mainObject.setBelongModel(null);
		}
		mainObject = value;
		if (mainObject != null) {
			mainObject.setBelongModel(this);
		}
	}

	/**
	 * 主节点主键字段Id
	 */
	public final String getPrimayKeyID() {
		String result;
		if (getMainObject() == null || getMainObject().getColumnGenerateID() == null) {
			result = "";
		} else {
			String text = getMainObject().getColumnGenerateID().getElementID();
			IGspCommonElement element = findElementById(text);
			if (element != null) {
				text = element.getLabelID();
			}
			result = (text != null) ? text : "";
		}
		return result;
	}

	public boolean isSimplifyGen() {
		return isSimplifyGen;
	}

	public void setSimplifyGen(boolean simplifyGen) {
		isSimplifyGen = simplifyGen;
	}

	public boolean isSimpBeanConfig() {
		return isSimpBeanConfig;
	}

	public void setSimpBeanConfig(boolean simpBeanConfig) {
		isSimpBeanConfig = simpBeanConfig;
	}

	private String generatingAssembly = "";

	public String getGeneratingAssembly() {
		return generatingAssembly;
	}

	public void setGeneratingAssembly(String value) {
		generatingAssembly = value;
	}


	private String generatingDotnetAssembly = "";

	public String getDotnetGeneratingAssembly() {
		return generatingDotnetAssembly;
	}

	public void setDotnetGeneratingAssembly(String value) {
		generatingDotnetAssembly = value;
	}
	/**
	 * 变量实体
	 */
	public CommonVariableEntity getVariables() {
		return variables;
	}

	public void setVariables(CommonVariableEntity value) {
		variables = value;
	}

	/**
	 * 是否使用命名空间+编号的ConfigId 以前建的为false，保证原有代码可用 新建元数据为true，保证后续元数据ConfigId唯一
	 */
	private boolean privateIsUseNamespaceConfig = false;

	public final boolean getIsUseNamespaceConfig() {
		return privateIsUseNamespaceConfig;
	}

	public final void setIsUseNamespaceConfig(boolean value) {
		privateIsUseNamespaceConfig = value;
	}

	private VersionControlInfo privateVersionContronInfo;

	public final VersionControlInfo getVersionContronInfo() {
		if (privateVersionContronInfo == null) {
			privateVersionContronInfo = new VersionControlInfo();
		}
		return privateVersionContronInfo;
	}

	public final void setVersionContronInfo(VersionControlInfo value) {
		privateVersionContronInfo = value;
	}

	/**
	 * 国际化项前缀
	 */
	private String privateI18nResourceInfoPrefix;

	public final String getI18nResourceInfoPrefix() {
		return privateI18nResourceInfoPrefix;
	}

	public final void setI18nResourceInfoPrefix(String value) {
		privateI18nResourceInfoPrefix = value;
	}

	// endregion

	// region 方法

	// region 获取字段

	/**
	 * 根据Id查找特定字段
	 *
	 * @param elementId
	 * @return
	 */
	public final IGspCommonElement findElementById(String elementId) {
		if (getMainObject().getContainElements() != null && getMainObject().getContainElements().size() > 0) {
			for (int i = 0; i < getMainObject().getContainElements().size(); i++) {
				IGspCommonElement element = getMainObject().getContainElements().getItem(i);
				element = findElementFromElementById(element, elementId);
				if (element != null) {
					return element;
				}
			}
			for (int i = 0; i < getMainObject().getContainChildObjects().size(); i++) {
				IGspCommonObject childObject = getMainObject().getContainChildObjects().get(i);
				IGspCommonElement element;
				for (int j = 0; j < childObject.getContainElements().size(); j++) {
					element = childObject.getContainElements().getItem(j);
					element = findElementFromElementById(element, elementId);
					if (element != null) {
						return element;
					}
				}
				element = findEleInChildObject(childObject, elementId);
				if (element != null) {
					return element;
				}
			}
		}

		return null;
	}

	private IGspCommonElement findElementFromElementById(IGspCommonElement ele, String elementId) {
		IGspCommonElement result;
		if (elementId.equals(ele.getID())) {
			result = ele;
		} else {
			if (ele.getHasAssociation()) {
				for (int i = 0; i < ele.getChildAssociations().size(); i++) {
					GspAssociation association =  ele.getChildAssociations().get(i);
					for (int j = 0; j < association.getRefElementCollection().size(); j++) {
						IGspCommonElement element = findElementFromElementById(
								(IGspCommonElement) association.getRefElementCollection().get(j), elementId);
						if (element != null) {
							result = element;
							return result;
						}
					}
				}
			}
			result = null;
		}
		return result;
	}

	private IGspCommonElement findEleInChildObject(IGspCommonObject absObject, String elementId) {
		if (absObject.getContainChildObjects() != null && absObject.getContainChildObjects().size() > 0) {
			for (int k = 0; k < absObject.getContainChildObjects().size(); k++) // 子对象的循环
			{
				IGspCommonObject child = absObject.getContainChildObjects().get(k);
				for (int i = 0; i < child.getContainElements().size(); i++) // 包含元素循环
				{
					IGspCommonElement ele = child.getContainElements().getItem(i);
					ele = findElementFromElementById(ele, elementId);
					if (ele != null) {
						return ele;
					}
				}
				findEleInChildObject(child, elementId); // 递归实现对多层子对象的查找
			}
		}
		return null;
	}

	/**
	 * 获取所有节点的所有字段
	 *
	 * @param containRef 是否包含关联带出字段
	 * @return
	 */
	public final ArrayList<IGspCommonElement> getAllElementList(boolean containRef) {
		ArrayList<IGspCommonElement> elements = new ArrayList<IGspCommonElement>();
		ArrayList<IGspCommonObject> objectList = getAllObjectList();
		for (IGspCommonObject commonObject : objectList) {
			elements.addAll(commonObject.getAllElementList(containRef));
		}
		return elements;
	}

	/**
	 * 获取所有字段
	 *
	 * @return
	 */
	public final ArrayList<IGspCommonElement> getAllObjectElementList() {
		ArrayList<IGspCommonElement> elementList = new ArrayList<IGspCommonElement>();
		ArrayList<IGspCommonObject> objects = getAllObjectList();
		for (IGspCommonObject commonObject : objects) {
			elementList.addAll(commonObject.getAllElementList(true));
		}
		return elementList;
	}

	/**
	 * 使用先根方式获取素有结点
	 *
	 * @return
	 */
	public final ArrayList<IGspCommonObject> getAllObjectList() {
		// 通过堆栈递归取子孙节点，有空测一下复杂的场景对不对 ZhangJ2015年12月17日
		java.util.Stack<IGspCommonObject> stack = new java.util.Stack<IGspCommonObject>();
		ArrayList<IGspCommonObject> objectList = new ArrayList<IGspCommonObject>();
		if (mainObject == null) {
			return objectList;
		}
		stack.push(mainObject);
		while (stack.size() > 0) {
			IGspCommonObject obj = stack.pop();
			objectList.add(obj);
			for (IGspCommonObject childObj : obj.getContainChildObjects()) {
				stack.push(childObj);
			}
		}
		return objectList;
	}

	/**
	 * 根据代码查找节点
	 *
	 * @param code
	 * @return
	 */
	public final IGspCommonObject findObjectByCode(String code) {
		for (IGspCommonObject obj : getAllObjectList()) {
			if (code.equals(obj.getCode())) {
				return obj;
			}
		}
		return null;
	}

	/**
	 * 根据Id查找节点
	 *
	 * @param objectId 节点Id
	 * @return
	 */
	public final IGspCommonObject findObjectById(String objectId) {
		for (IGspCommonObject obj : getAllObjectList()) {
			if (objectId.equals(obj.getID())) {
				return obj;
			}
		}
		return null;
	}
	// endregion

	/**
	 * 获取主键Id集合
	 *
	 * @return
	 */
	public final ArrayList<String> getPKConstraintIDList() {
		ArrayList<String> pkConstraintIdList = new ArrayList<String>();
		ArrayList<IGspCommonElement> elementList = getAllElementList(true);

		for (IGspCommonElement element : elementList) {
			if (element.getHasAssociation()) {
				for (GspAssociation item : element.getChildAssociations()) {
					GspCommonAssociation association = (GspCommonAssociation) item;
					pkConstraintIdList.add(association.getId());
				}

			}
		}
		return pkConstraintIdList;
	}

	/**
	 * 克隆
	 *
	 * @return
	 */
	public GspCommonModel clone() {
		GspCommonModel tempVar;
		try {
			tempVar = (GspCommonModel) super.clone();
		} catch (CloneNotSupportedException e) {
			return null;
		}
		GspCommonModel absModel = (GspCommonModel) ((tempVar instanceof GspCommonModel) ? tempVar : null);
		if (absModel != null) {
			IGspCommonObject tempVar2 = mainObject.clone(mainObject.getParentObject());
			absModel.mainObject = (GspCommonObject) ((tempVar2 instanceof GspCommonObject) ? tempVar2 : null);
		}
		return absModel;
	}

	// todo: Cef runtime 引用
//	/**
//	 * 字段编号、标签转camel
//	 * @return
//	 */
//	public GspCommonModel convertToCamelCaseProperty() {
//		GspCommonModel be = clone();
//		be.getAllElementList(true).stream().forEach(item -> {
//			item.setCode(StringUtils.toCamelCase(item.getCode()));
//			item.setLabelID(StringUtils.toCamelCase(item.getLabelID()));
//		});
//		return be;
//	}


	private String getLowerCaseModelCode() {
		return getCode().toLowerCase();
	}

	@Override
	public DataTypeAssemblyInfo getCoreAssemblyInfo() {
		String assName = String.format("%1$s.%2$s.%3$s", getGeneratingAssembly(), this.getLowerCaseModelCode(),
				coreNamespaceSuffix);
		return new DataTypeAssemblyInfo(assName, assName);
	}

	@Override
	public DataTypeAssemblyInfo getEntityAssemblyInfo() {
		String assName = String.format("%1$s.%2$s.%3$s", getGeneratingAssembly(), this.getLowerCaseModelCode(),
				entityNamespaceSuffix);
		return new DataTypeAssemblyInfo(assName, assName);
	}

	private static final String coreNamespaceSuffix = "core";
	private static final String entityNamespaceSuffix = "entity";

	private static final String apiNamespaceSuffix = "api";

	@Override
	public DataTypeAssemblyInfo getApiNamespace() {
		String assName = String.format("%1$s.%2$s.%3$s", getGeneratingAssembly(), this.getLowerCaseModelCode(), apiNamespaceSuffix);
		return new DataTypeAssemblyInfo(assName, assName);
	}

	public final String getGeneratedConfigID() {
		if (getIsUseNamespaceConfig()) {
			return getGeneratingAssembly() + "." + getCode();
		}
		return getCode();
	}
	public final String getDotnetGeneratedConfigID() {
		if (getIsUseNamespaceConfig()) {
			return getDotnetGeneratingAssembly() + "." + getCode();
		}
		return getCode();
	}
	// endregion

	// endregion

	// region EntityObject
	@JsonIgnore
	@Override
	public final String getId() {
		return getID();
	}

	@Override
	public final String getUri() {
		return "";
	}

	private String description;

	@Override
	public String getDescription() {
		return description;
	}

	public void setDescription(String value){
		description = value;
	}

	@Override
	public final List<StructuredType> getStructuredTypes() {
		List<StructuredType> list = new ArrayList<>();
		buildObjStructureTypes(list, getMainObject());
		return list;
	}

	// region getStructuredTypes
	private void buildObjStructureTypes(List<StructuredType> list, GspCommonObject obj) {
		list.add(obj);
		for (IGspCommonField element : obj.getContainElements()) {
			buildElementStructureTypes(list, (GspCommonElement) element);
		}
		for (IGspCommonObject childObj : obj.getContainChildObjects()) {
			buildObjStructureTypes(list, (GspCommonObject) childObj);
		}
	}

	private void buildElementStructureTypes(List<StructuredType> list, GspCommonElement element) {
		// 仅添加非UDT的普通枚举
		if (element.getIsUdt()) {
			return;
		}
		if (element.getObjectType() != GspElementObjectType.Enum) {
			return;
		}
		list.add((StructuredType) element.getPropertyType());
	}


	// endregion

	@Override
	public final List<CommonStructure> getRefStructures() {
		return getCommonModelRefStructures();
	}

	// region getRefStructures
	protected List<CommonStructure> getCommonModelRefStructures() {
		// 子类实现
		throw new NotImplementedException();
	}
	// endregion

	@Override
	public final String getKind() {
		return new DefaultEntityObject().getKind();
	}

	@Override
	public final List<Operation> getOperations() {
		return getCommonModelOperations();
	}

	@Override
	public final Map<String, Map<String, List<EntityRelation>>> getEntityRelations() {
		Map<String, Map<String, List<EntityRelation>>> relationDic = new HashMap<>();
		buildEntityRelations(getMainObject(), relationDic);
		return relationDic;
	}

	// region GetEntityRelations
	private void buildEntityRelations(IGspCommonObject mainObject,
	                                  Map<String, Map<String, List<EntityRelation>>> relationDic) {
		for (IGspCommonObject childObj : mainObject.getContainChildObjects()) {
			// 外键
			String childObjParentIdEle = childObj.findElement(childObj.getKeys().get(0).getSourceElement()).getLabelID();
			String idEle = mainObject.findElement(childObj.getKeys().get(0).getTargetElement()).getLabelID();
			relationDic.put(mainObject.getID(), createEntityRelationDic(childObj.getID(), idEle, childObjParentIdEle));
			// 递归
			buildEntityRelations(childObj, relationDic);
		}

	}

	private Map<String, List<EntityRelation>> createEntityRelationDic(String childObjId, String parentCode,
	                                                                  String childCode) {
		Map<String, List<EntityRelation>> dic = new HashMap<>();
		EntityRelation relation = createEntityRelation(parentCode, childCode);
		List<EntityRelation> list = new ArrayList<>();
		list.add(relation);
		dic.put(childObjId, list);
		return dic;
	}

	private EntityRelation createEntityRelation(String parentCode, String childCode) {
		EntityRelation relation = new EntityRelation();
		relation.setParentCode(parentCode);
		relation.setChildCode(childCode);
		return relation;
	}
	// endregion

	@Override
	public final StructuredType getRoot() {
		return getMainObject();
	}

	@Override
	public final List<String> getExtensionKeys() {
		return null;
	}

	@Override
	public final String getExtensionValue(String s) {
		return null;
	}


	protected List<Operation> getCommonModelOperations() {
		return new ArrayList<Operation>();
	}
	// endregion
}
